package com.jinly.ryder.common.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jinly.ryder.common.dao.SettingItemMapper;
import com.jinly.ryder.common.dao.entity.SettingItemDO;
import com.jinly.ryder.common.service.SettingItemService;
import com.jinly.ryder.common.service.mapping.SettingItemMapping;
import com.jinly.ryder.common.service.model.SettingCategory;
import com.jinly.ryder.common.service.model.SettingItem;
import com.jinly.ryder.common.service.model.SettingModel;
import com.jinly.ryder.common.service.model.SettingRefKey;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Slf4j
@Service
@RequiredArgsConstructor
public class SettingItemServiceImpl implements SettingItemService {

    private final SettingItemMapper settingItemMapper;
    private final SettingItemMapping settingItemMapping;

    @Override
    public void saveSettingItem(Object object) {
        SettingItem refKeyItem = getRefKeyItem(object);
        if (refKeyItem == null) return;
        List<SettingItem> itemList = new ArrayList<>();
        Field[] fields = object.getClass().getDeclaredFields();
        for (Field field : fields) {
            SettingModel settingModel = field.getType().getAnnotation(SettingModel.class);
            if (settingModel != null) {
                field.setAccessible(true);
                Object value = ReflectionUtils.getField(field, object);
                SettingItem item = new SettingItem();
                item.setCategory(refKeyItem.getCategory());
                item.setRefKey(refKeyItem.getRefKey());
                item.setItemName(settingModel.name());
                item.setItemValue(JSON.toJSONString(value));
                itemList.add(item);
            }
        }
        saveList(itemList);
    }


    private void saveList(List<SettingItem> itemList) {
        for (SettingItem item : itemList) {
            SettingItem his = getItem(item.getRefKey(), item.getCategory(), item.getItemName());
            if (his == null) {
                settingItemMapper.insert(settingItemMapping.toEntity(item));
            } else {
                his.setItemValue(item.getItemValue());
                settingItemMapper.updateById(settingItemMapping.toEntity(his));
            }
        }
    }

    private SettingItem getItem(String refKey, SettingCategory category, String itemName) {
        Wrapper<SettingItemDO> queryWrapper = new QueryWrapper<SettingItemDO>().lambda()
                .eq(SettingItemDO::getRefKey, refKey)
                .eq(SettingItemDO::getCategory, category)
                .eq(SettingItemDO::getItemName, itemName)
                .last("limit 1");
        return settingItemMapping.toModel(settingItemMapper.selectOne(queryWrapper));
    }

    @Override
    public <T> T getItem(String refKey, SettingCategory category, Class<T> tClass) {
        SettingModel settingModel = tClass.getAnnotation(SettingModel.class);
        if (settingModel != null) {
            SettingItem item = getItem(refKey, category, settingModel.name());
            if (item != null) {
                return JSON.parseObject(item.getItemValue(), tClass);
            }
        }
        return null;
    }

    @Override
    public void setSettingItem(Object object) {
        SettingItem refKeyItem = getRefKeyItem(object);
        if (refKeyItem == null) return;
        List<SettingItem> itemList = getItemList(refKeyItem.getRefKey(), refKeyItem.getCategory());
        if (itemList.size() == 0) return;
        Field[] fields = object.getClass().getDeclaredFields();
        for (Field field : fields) {
            SettingModel settingModel = field.getType().getAnnotation(SettingModel.class);
            if (settingModel != null) {
                field.setAccessible(true);
                itemList.stream()
                        .filter(i -> Objects.equals(i.getItemName(), settingModel.name()))
                        .findFirst()
                        .ifPresent(i -> {
                            Object value = JSON.parseObject(i.getItemValue(), field.getType());
                            ReflectionUtils.setField(field, object, value);
                        });
            }
        }
    }

    private SettingItem getRefKeyItem(Object object) {
        if (object == null) return null;
        Field[] fields = object.getClass().getDeclaredFields();
        for (Field field : fields) {
            SettingRefKey settingRefKey = field.getAnnotation(SettingRefKey.class);
            if (settingRefKey != null) {
                field.setAccessible(true);
                field.setAccessible(true);
                Object value = ReflectionUtils.getField(field, object);
                if (value != null) {
                    SettingItem keyItem = new SettingItem();
                    keyItem.setRefKey(value.toString());
                    keyItem.setCategory(settingRefKey.category());
                    return keyItem;
                }
            }
        }
        return null;
    }

    private List<SettingItem> getItemList(String refKey, SettingCategory category) {
        Wrapper<SettingItemDO> queryWrapper = new QueryWrapper<SettingItemDO>().lambda()
                .eq(SettingItemDO::getRefKey, refKey)
                .eq(SettingItemDO::getCategory, category);
        return settingItemMapping.toModelList(settingItemMapper.selectList(queryWrapper));
    }

}
